home *** CD-ROM | disk | FTP | other *** search
/ By Popular Request 2.0 / By Popular Request 2.0 (Arsenal Computer).ISO / amiga_4 / named.lha / named.c < prev    next >
C/C++ Source or Header  |  1995-03-21  |  13KB  |  514 lines

  1. /*
  2. **
  3. **        AmiTCP Dumb Nameserver
  4. **      ----------------------
  5. **        Amiga version hacked & slain by Oliver Wagner (o.wagner@pluribus.wupper.de)
  6. **
  7. **        very loosely based on JoranNameserver for AmiTCP 2.x
  8. **
  9. **        compile with SAS/C 6.55
  10. **
  11. */
  12.  
  13. #include <bsdsocket.h>
  14. #include <syslog.h>
  15.  
  16. #define BYTE_ORDER BIG_ENDIAN
  17. #include <arpa/nameser.h>
  18. #include <sys/types.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <netdb.h>
  22.  
  23. // Amiga stuff
  24. #include <proto/dos.h>
  25. #include <dos/stdio.h>
  26. #include <proto/utility.h>
  27.  
  28. #include <string.h>
  29.  
  30. #include "rev.h"
  31. char version[] = {á"$VER: AmiTCP-NameServer " VERTAG };
  32.  
  33. long __oslibversion = 37;
  34.  
  35. /*
  36.  * ++Copyright++ 1985
  37.  * -
  38.  * Copyright (c) 1985 Regents of the University of California.
  39.  * All rights reserved.
  40.  * 
  41.  * Redistribution and use in source and binary forms, with or without
  42.  * modification, are permitted provided that the following conditions
  43.  * are met:
  44.  * 1. Redistributions of source code must retain the above copyright
  45.  *    notice, this list of conditions and the following disclaimer.
  46.  * 2. Redistributions in binary form must reproduce the above copyright
  47.  *    notice, this list of conditions and the following disclaimer in the
  48.  *    documentation and/or other materials provided with the distribution.
  49.  * 3. All advertising materials mentioning features or use of this software
  50.  *    must display the following acknowledgement:
  51.  *     This product includes software developed by the University of
  52.  *     California, Berkeley and its contributors.
  53.  * 4. Neither the name of the University nor the names of its contributors
  54.  *    may be used to endorse or promote products derived from this software
  55.  *    without specific prior written permission.
  56.  * 
  57.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  58.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  59.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  60.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  61.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  62.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  63.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  64.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  65.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  66.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  67.  * SUCH DAMAGE.
  68.  * -
  69.  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
  70.  * 
  71.  * Permission to use, copy, modify, and distribute this software for any
  72.  * purpose with or without fee is hereby granted, provided that the above
  73.  * copyright notice and this permission notice appear in all copies, and that
  74.  * the name of Digital Equipment Corporation not be used in advertising or
  75.  * publicity pertaining to distribution of the document or software without
  76.  * specific, written prior permission.
  77.  * 
  78.  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  79.  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  80.  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  81.  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  82.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  83.  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  84.  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  85.  * SOFTWARE.
  86.  * -
  87.  * --Copyright--
  88.  */
  89.  
  90. /*
  91.  * Expand compressed domain name 'comp_dn' to full domain name.
  92.  * 'msg' is a pointer to the begining of the message,
  93.  * 'eomorig' points to the first location after the message,
  94.  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
  95.  * Return size of compressed name or -1 if there was an error.
  96.  */
  97. static dn_expand(const u_char *msg, const u_char *eomorig, const u_char *comp_dn, u_char *exp_dn, int length)
  98. {
  99.      u_char *cp, *dn;
  100.      int n, c;
  101.     u_char *eom;
  102.     int len = -1, checked = 0;
  103.  
  104.     dn = exp_dn;
  105.     cp = (u_char *)comp_dn;
  106.     eom = exp_dn + length;
  107.     /*
  108.      * fetch next label in domain name
  109.      */
  110.     while (n = *cp++) {
  111.         /*
  112.          * Check for indirection
  113.          */
  114.         switch (n & INDIR_MASK) {
  115.         case 0:
  116.             if (dn != exp_dn) {
  117.                 if (dn >= eom)
  118.                     return (-1);
  119.                 *dn++ = '.';
  120.             }
  121.             if (dn+n >= eom)
  122.                 return (-1);
  123.             checked += n + 1;
  124.             while (--n >= 0) {
  125.                 if ((c = *cp++) == '.') {
  126.                     if (dn + n + 2 >= eom)
  127.                         return (-1);
  128.                     *dn++ = '\\';
  129.                 }
  130.                 *dn++ = c;
  131.                 if (cp >= eomorig)    /* out of range */
  132.                     return(-1);
  133.             }
  134.             break;
  135.  
  136.         case INDIR_MASK:
  137.             if (len < 0)
  138.                 len = cp - comp_dn + 1;
  139.             cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff));
  140.             if (cp < msg || cp >= eomorig)    /* out of range */
  141.                 return(-1);
  142.             checked += 2;
  143.             /*
  144.              * Check for loops in the compressed name;
  145.              * if we've looked at the whole message,
  146.              * there must be a loop.
  147.              */
  148.             if (checked >= eomorig - msg)
  149.                 return (-1);
  150.             break;
  151.  
  152.         default:
  153.             return (-1);            /* flag error */
  154.         }
  155.     }
  156.     *dn = '\0';
  157.     if (len < 0)
  158.         len = cp - comp_dn;
  159.     return (len);
  160. }
  161.  
  162. /*
  163.  * Search for expanded name from a list of previously compressed names.
  164.  * Return the offset from msg if found or -1.
  165.  * dnptrs is the pointer to the first name on the list,
  166.  * not the pointer to the start of the message.
  167.  */
  168. static int dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, u_char **lastdnptr)
  169. {
  170.      u_char *dn, *cp, **cpp;
  171.      int n;
  172.     u_char *sp;
  173.  
  174.     for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
  175.         dn = exp_dn;
  176.         sp = cp = *cpp;
  177.         while (n = *cp++) {
  178.             /*
  179.              * check for indirection
  180.              */
  181.             switch (n & INDIR_MASK) {
  182.             case 0:        /* normal case, n == len */
  183.                 while (--n >= 0) {
  184.                     if (*dn == '.')
  185.                         goto next;
  186.                     if (*dn == '\\')
  187.                         dn++;
  188.                     if (*dn++ != *cp++)
  189.                         goto next;
  190.                 }
  191.                 if ((n = *dn++) == '\0' && *cp == '\0')
  192.                     return (sp - msg);
  193.                 if (n == '.')
  194.                     continue;
  195.                 goto next;
  196.  
  197.             default:    /* illegal type */
  198.                 return (-1);
  199.  
  200.             case INDIR_MASK:    /* indirection */
  201.                 cp = msg + (((n & 0x3f) << 8) | *cp);
  202.             }
  203.         }
  204.         if (*dn == '\0')
  205.             return (sp - msg);
  206.     next:    ;
  207.     }
  208.     return (-1);
  209. }
  210.  
  211. /*
  212.  * Compress domain name 'exp_dn' into 'comp_dn'.
  213.  * Return the size of the compressed name or -1.
  214.  * 'length' is the size of the array pointed to by 'comp_dn'.
  215.  * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
  216.  * is a pointer to the beginning of the message. The list ends with NULL.
  217.  * 'lastdnptr' is a pointer to the end of the arrary pointed to
  218.  * by 'dnptrs'. Side effect is to update the list of pointers for
  219.  * labels inserted into the message as we compress the name.
  220.  * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
  221.  * is NULL, we don't update the list.
  222.  */
  223. static dn_comp( const u_char *exp_dn, u_char *comp_dn, int length, u_char **dnptrs, u_char **lastdnptr)
  224. {
  225.      u_char *cp, *dn;
  226.      int c, l;
  227.     u_char **cpp, **lpp, *sp, *eob;
  228.     u_char *msg;
  229.  
  230.     dn = (u_char *)exp_dn;
  231.     cp = comp_dn;
  232.     eob = cp + length;
  233.     if (dnptrs != NULL) {
  234.         if ((msg = *dnptrs++) != NULL) {
  235.             for (cpp = dnptrs; *cpp != NULL; cpp++)
  236.                 ;
  237.             lpp = cpp;    /* end of list to search */
  238.         }
  239.     } else
  240.         msg = NULL;
  241.     for (c = *dn++; c != '\0'; ) {
  242.         /* look to see if we can use pointers */
  243.         if (msg != NULL) {
  244.             if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
  245.                 if (cp+1 >= eob)
  246.                     return (-1);
  247.                 *cp++ = (l >> 8) | INDIR_MASK;
  248.                 *cp++ = l % 256;
  249.                 return (cp - comp_dn);
  250.             }
  251.             /* not found, save it */
  252.             if (lastdnptr != NULL && cpp < lastdnptr-1) {
  253.                 *cpp++ = cp;
  254.                 *cpp = NULL;
  255.             }
  256.         }
  257.         sp = cp++;    /* save ptr to length byte */
  258.         do {
  259.             if (c == '.') {
  260.                 c = *dn++;
  261.                 break;
  262.             }
  263.             if (c == '\\') {
  264.                 if ((c = *dn++) == '\0')
  265.                     break;
  266.             }
  267.             if (cp >= eob) {
  268.                 if (msg != NULL)
  269.                     *lpp = NULL;
  270.                 return (-1);
  271.             }
  272.             *cp++ = c;
  273.         } while ((c = *dn++) != '\0');
  274.         /* catch trailing '.'s but not '..' */
  275.         if ((l = cp - sp - 1) == 0 && c == '\0') {
  276.             cp--;
  277.             break;
  278.         }
  279.         if (l <= 0 || l > MAXLABEL) {
  280.             if (msg != NULL)
  281.                 *lpp = NULL;
  282.             return (-1);
  283.         }
  284.         *sp = l;
  285.     }
  286.     if (cp >= eob) {
  287.         if (msg != NULL)
  288.             *lpp = NULL;
  289.         return (-1);
  290.     }
  291.     *cp++ = '\0';
  292.     return (cp - comp_dn);
  293. }
  294.  
  295. // -------------------------------------------------------------------------
  296.  
  297. /*
  298. **    Amiga specific stuff
  299. */
  300.  
  301. /*
  302. **    Format of host entries
  303. */
  304.  
  305. #define ENTRYTIMEOUT (3600*24*90)    // 90 Days timeout
  306.  
  307. struct nsdbentry {
  308.     time_t read;        // When entry was created
  309.     ULONG ip;
  310.     ULONG hash;
  311.     UBYTE name[á244 ];
  312. };
  313.  
  314. //
  315. // We do some hashing to avoid numerous stricmp()s
  316. //
  317. static ULONG hash( char *name )
  318. {
  319.     ULONG val = strlen( name );
  320.  
  321.     while( *name )
  322.         val = ( val * 13 ) + ( ToUpper( *name++ ) );
  323.  
  324.     return( val );
  325. }
  326.  
  327. static ULONG findhost( char *name )
  328. {
  329.     BPTR fh = Open( "AmiTCP:db/nameserver.db", MODE_OLDFILE );
  330.     ULONG myhash = hash( name );
  331.     struct nsdbentry ns;
  332.     time_t limit = time( NULL ) - ENTRYTIMEOUT;
  333.     int toold = FALSE;
  334.     struct hostent *host;
  335.  
  336.     // First, look into table
  337.     if( fh )
  338.     {
  339.         SetVBuf( fh, NULL, BUF_FULL, 16384 );
  340.         Flush( fh );
  341.  
  342.         while( FRead( fh, &ns, sizeof( ns ), 1 ) == 1 )
  343.         {
  344.             // Found!
  345.             if( ns.hash == myhash && !stricmp( ns.name, name ) )
  346.             {
  347.                 if( ns.read >= limit )
  348.                 {
  349.                     // ok!
  350.                     Close( fh );
  351.                     return( ns.ip );
  352.                 }
  353.                 // Found, but too old
  354.                 toold = TRUE;
  355.                 break;
  356.             }
  357.         }
  358.     }
  359.  
  360.     // We need to do a real lookup
  361.     host = gethostbyname( name );
  362.     if( !host )
  363.     {
  364.         if( fh )
  365.             Close( fh );
  366.         return( ~0 );
  367.     }
  368.  
  369.     // Create entry
  370.     time( &ns.read );
  371.     memcpy( &ns.ip, &host->h_addr_list[á0 ][á0 ], 4 );
  372.     ns.hash = myhash;
  373.     strncpy( ns.name, name, 243 );    // This really sucks...
  374.     ns.name[á243 ]á= 0;
  375.  
  376.     if( !fh )
  377.         fh = Open( "AmiTCP:db/nameserver.db", MODE_NEWFILE );
  378.     if( fh )
  379.     {
  380.         Flush( fh );
  381.         if( toold )
  382.             Seek( fh, -sizeof ns , OFFSET_CURRENT );
  383.         else
  384.             Seek( fh, 0, OFFSET_END );
  385.         Write( fh, &ns, sizeof ns );
  386.         Close( fh );
  387.     }
  388.  
  389.     return( ns.ip );
  390. }
  391.  
  392. static void send_err( int s, char *msg, int msglen, struct sockaddr_in *to, LONG tolen, short rcode )
  393. {
  394.     HEADER *h;
  395.     
  396.     h = ( HEADER * ) msg + sizeof( HEADER );
  397.     h->qr = 1;
  398.     h->rcode = rcode;
  399.     sendto( s, msg, msglen, 0, ( struct sockaddr * ) to, tolen );
  400.  
  401. }
  402.  
  403. void __stdargs __main( char *dummy )
  404. {
  405.     int s;                        /* Datagram socket */
  406.     struct sockaddr_in from;    /* Address of requestor */
  407.     int fromlen;                /* Length of his address */
  408.     int msglen;                    /* Length of the message received */
  409.     ULONG ip;
  410.     UBYTE msg[á512 ], *cp, *eom, dnbuf[á512 ], *lmsg;
  411.     HEADER *h;
  412.     int n, type, class;
  413.     ULONG xxx = 100000;
  414.  
  415.     s = init_inet_daemon();
  416.     if( s < 0 )
  417.         exit( 20 );
  418.  
  419.     SetProgramName( "NameD" );
  420.  
  421.     openlog( "NameD", LOG_PID | LOG_CONS, LOG_DAEMON );
  422.  
  423.     fromlen = sizeof( from );    
  424.  
  425.     /* Main loop */
  426.     for(;;)
  427.     {
  428.         if( CheckSignal( SIGBREAKF_CTRL_C ) )
  429.             break;
  430.  
  431.         /* Read a message */
  432.         fromlen = sizeof(from);
  433.         if( ( msglen = recvfrom( s, msg, sizeof( msg ), 0, (struct sockaddr *)&from, &fromlen ) ) == -1 )
  434.         {
  435.             syslog( LOG_ERR, "recvfrom() error %ld", Errno() );
  436.             continue;
  437.         }
  438.         h = ( HEADER * ) msg;
  439.  
  440.         if( h->opcode != QUERY )
  441.         {
  442.             send_err( s, msg, msglen, &from, fromlen, NOTIMP );
  443.             continue;
  444.         }
  445.  
  446.         cp = msg + sizeof( HEADER );
  447.         eom = msg + msglen;
  448.  
  449.         // Only simple requests
  450.         if( h->qdcount != 1 || h->ancount || h->nscount || h->arcount )
  451.         {
  452.             h->qdcount = 0;
  453.             h->ancount = 0;
  454.             h->nscount = 0;
  455.             h->arcount = 0;
  456.             send_err( s, msg, msglen, &from, fromlen, FORMERR );
  457.             continue;
  458.         }
  459.         if( ( n = dn_expand( msg, eom, cp, dnbuf, sizeof( dnbuf ) ) ) < 0 )
  460.         {
  461.             send_err(s,msg,msglen,&from,fromlen,FORMERR);
  462.             continue;
  463.         }
  464.         cp += n;
  465.         GETSHORT( type, cp );
  466.         GETSHORT( class, cp );
  467.         if( cp > eom )
  468.         {
  469.             send_err( s, msg, msglen, &from, fromlen, FORMERR );
  470.             continue;
  471.         }
  472.         if( type != T_A || class != C_IN )
  473.         {
  474.             send_err(s,msg,msglen,&from,fromlen,NOTIMP);
  475.             continue;
  476.         }
  477.  
  478.         // find IP address of host
  479.         ip = findhost( dnbuf );
  480.             
  481.         if( ip == ~0 )
  482.         {
  483.             send_err( s, msg, msglen, &from, fromlen, NXDOMAIN );
  484.             continue;
  485.         }
  486.         
  487.         lmsg = msg + sizeof( msg );
  488.         if( ( n = dn_comp( dnbuf, cp, lmsg - cp, NULL, NULL ) ) < 0 )
  489.         {
  490.             send_err( s, msg, msglen, &from, fromlen, SERVFAIL );
  491.             continue;                        
  492.         }
  493.         cp += n;
  494.         if( cp + 14 > lmsg )
  495.         {
  496.             send_err( s, msg, msglen, &from, fromlen, SERVFAIL );
  497.             continue;            
  498.         }
  499.         
  500.         PUTSHORT( type, cp );
  501.         PUTSHORT( class, cp );
  502.         PUTLONG( xxx, cp );
  503.         PUTSHORT( sizeof( LONG ), cp );
  504.         PUTLONG( ip, cp );
  505.         
  506.         h->qr = 1;
  507.         h->rcode = NOERROR;
  508.         h->ancount = 1;
  509.         sendto( s, msg, cp - msg, 0, ( struct sockaddr * ) &from, fromlen );
  510.     }
  511. }
  512.  
  513. // EOF
  514.